#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>


#if 0
struct msghdr {
    void         *msg_name;       /* optional address */
    socklen_t     msg_namelen;    /* size of address */
    struct iovec *msg_iov;        /* scatter/gather array */
    size_t        msg_iovlen;     /* # elements in msg_iov */
    void         *msg_control;    /* ancillary data, see below */
    size_t        msg_controllen; /* ancillary data buffer len */
    int           msg_flags;      /* flags (unused) */
};

struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};

/* Structure used for storage of ancillary data object information.  */
struct cmsghdr
  {
    size_t cmsg_len;        /* Length of data in cmsg_data plus length
                   of cmsghdr structure.
                   !! The type should be socklen_t but the
                   definition of the kernel is incompatible
                   with this.  */
    int cmsg_level;     /* Originating protocol.  */
    int cmsg_type;      /* Protocol specific type.  */
#if __glibc_c99_flexarr_available
    __extension__ unsigned char __cmsg_data __flexarr; /* Ancillary data.  */
#endif
  };

/* Socket level message types.  This must match the definitions in
   <linux/socket.h>.  */
enum
  {
    SCM_RIGHTS = 0x01       /* Transfer file descriptors.  */
#define SCM_RIGHTS SCM_RIGHTS
#ifdef __USE_GNU
    , SCM_CREDENTIALS = 0x02    /* Credentials passing.  */
# define SCM_CREDENTIALS SCM_CREDENTIALS
#endif
  };


#endif


static struct cmsghdr *cmptr = NULL;

int send_fd(int fd, int fd_to_send) {
    struct iovec iov[1]; // msg包含的多个缓冲区构成的数组
    struct msghdr msg; // sendmsg 要发送的对象,或者recvmsg要接收的消息的信息
    char buf[2]; // send_fd/recv_fd 2-byte协议

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);

    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    if (fd_to_send < 0) {
        // 清空控制数据
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        buf[1] = -fd_to_send; // 非0 意味着错误

        if (buf[1] == 0)
            buf[1] = 1; // -256 等会弄乱协议
    }
    else {
        cmptr = (struct cmsghdr *)malloc(CMSG_LEN(sizeof(int)));
        if (cmptr == NULL) 
            return -1;
        cmptr->cmsg_level = SOL_SOCKET; // stream mode -- TCP
        cmptr->cmsg_type  = SCM_RIGHTS; // 传输文件描述符
        cmptr->cmsg_len   = CMSG_LEN(sizeof(int)) ;
        
        msg.msg_control = cmptr;
        msg.msg_controllen = fd_to_send; // 要传输的fd
        buf[1] = 0; // 状态0意味着OK
    }
    
    buf[0] = 0;
    if (sendmsg(fd, &msg, 0) != 2)
        return -1;

    return 0;
}

